package com.fanshuai;

import com.fanshuai.config.KubernetesConfig;
import io.fabric8.kubernetes.api.model.*;
import io.fabric8.kubernetes.api.model.apps.DaemonSet;
import io.fabric8.kubernetes.api.model.apps.DaemonSetList;
import io.fabric8.kubernetes.api.model.apps.Deployment;
import io.fabric8.kubernetes.api.model.apps.DeploymentList;
import io.fabric8.kubernetes.api.model.batch.Job;
import io.fabric8.kubernetes.api.model.batch.JobList;
import io.fabric8.kubernetes.client.KubernetesClient;
import io.fabric8.kubernetes.client.Watcher;
import io.fabric8.kubernetes.client.WatcherException;
import io.fabric8.kubernetes.client.dsl.ExecWatch;
import io.fabric8.kubernetes.client.dsl.LogWatch;

import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * Hello world!
 *
 */
public class App {
    static int core = Runtime.getRuntime().availableProcessors();
    static ExecutorService executorService = Executors.newFixedThreadPool(core);

    public static void main(String[] args) throws Exception {
        KubernetesClient client = KubernetesConfig.client;

        //testQueryNamespace(client);
        //testQueryNode(client);
        //testQueryPod(client);

        //testQueryDeployment(client);
        //testQueryJob(client);
        //testQueryDaemonSet(client);
        //testQueryService(client);
        //testQuerySecret(client);
        //testQueryConfigMap(client);
        //testQueryPersistentVolumes(client);
        //testQueryPersistentVolumeClaims(client);
        //testApplyDeployment(client);
        //testWatch(client);
        testWatchConsole("golangv1-79d7885b57-8pzq7", client);
        //testWatchLog("golangv1-74b7d64c99-p8646", client);
    }

    private static void testQueryNamespace(KubernetesClient client) {
        NamespaceList namespaceList = client.namespaces().list();
        namespaceList.getItems().forEach(namespace -> {
            System.out.println(namespace.getMetadata().getName() + ":" + namespace.getStatus().getPhase());
        });
    }

    private static void testQueryNode(KubernetesClient client) {
        NodeList nodeList = client.nodes().list();
        nodeList.getItems().forEach(node -> {
            System.out.println(node.getMetadata().getName() + ":" + node.getStatus().getPhase());
        });
    }

    private static void testQueryPod(KubernetesClient client) {
        PodList podList = client.pods().list();
        podList.getItems().forEach(pod -> {
            System.out.println(pod.getMetadata().getName() + ":" + pod.getSpec().getContainers().get(0).getName());
        });

        ListOptions listOptions = new ListOptions();
        listOptions.setLabelSelector("app=nginx-app");
        Pod nginxPod = client.pods().list(listOptions).getItems().get(0);
        System.out.println(nginxPod);

        listOptions.setLabelSelector("app=golangv1");
        Pod golangPod = client.pods().list(listOptions).getItems().get(0);
        System.out.println(golangPod);
    }

    private static void testQueryDeployment(KubernetesClient client) {
        DeploymentList deploymentList = client.apps().deployments().list();
        deploymentList.getItems().forEach(System.out::println);

        ListOptions listOptions = new ListOptions();
        listOptions.setLabelSelector("app=golangv1");
        Deployment golangv1 = client.apps().deployments().inNamespace("default").withName("golangv1").get();
        System.out.println(golangv1);

        client.apps().deployments().inNamespace("default").withName("golangv1").delete();
    }

    private static void testQueryJob(KubernetesClient client) {
        ListOptions listOptions = new ListOptions();
        JobList jobList = client.batch().jobs().list();
        jobList.getItems().forEach(System.out::println);

        Job job = client.batch().jobs().inNamespace("default").withName("hello-job").get();
        System.out.println("\n" + job);

        client.batch().jobs().inNamespace("default").withName("hello-job").delete();
    }

    private static void testQueryDaemonSet(KubernetesClient client) {
        DaemonSetList daemonSetList = client.apps().daemonSets().list();
        daemonSetList.getItems().forEach(System.out::println);

        DaemonSet daemonSet = client.apps().daemonSets().inNamespace("default").withName("daemon-demo01").get();
        System.out.println("\n" + daemonSet);
    }

    private static void testQueryService(KubernetesClient client) {
        ServiceList serviceList = client.services().list();
        serviceList.getItems().forEach(System.out::println);
    }

    private static void testQuerySecret(KubernetesClient client) {
        SecretList secretList = client.secrets().list();
        secretList.getItems().forEach(System.out::println);
    }

    private static void testQueryConfigMap(KubernetesClient client) {
        ConfigMapList configMapList = client.configMaps().list();
        configMapList.getItems().forEach(System.out::println);
    }

    private static void testQueryPersistentVolumes(KubernetesClient client) {
        PersistentVolumeList persistentVolumeList = client.persistentVolumes().list();
        persistentVolumeList.getItems().forEach(System.out::println);
    }

    private static void testQueryPersistentVolumeClaims(KubernetesClient client) {
        PersistentVolumeClaimList persistentVolumeClaimList = client.persistentVolumeClaims().list();
        persistentVolumeClaimList.getItems().forEach(System.out::println);
    }

    private static void testApplyDeployment(KubernetesClient client) {
        InputStream in = App.class.getResourceAsStream("/golang.yml");
        Deployment deployment = client.apps().deployments()
                .load(in).get();
        client.apps().deployments().inNamespace("default").createOrReplace(deployment);

        InputStream in2 = App.class.getResourceAsStream("/golang-service.yml");
        Service service = client.services().load(in2).get();
        KubernetesConfig.client.services().inNamespace("default").createOrReplace(service);
    }

    private static void testWatch(KubernetesClient client) {
        client.pods().inNamespace("default").watch(new Watcher<Pod>() {
            @Override
            public void eventReceived(Action action, Pod pod) {
                System.out.println("action=" + action.name() + ", pod={}" + pod.getMetadata().getName());
            }

            @Override
            public void onClose(WatcherException e) {

            }
        });
    }

    static class StdTask implements Runnable {
        InputStream inputStream;
        String taskId;
        public StdTask(InputStream in, String taskId) {
            this.inputStream = in;
            this.taskId = taskId;
        }

        @Override
        public void run() {
            try {
                byte[] data = new byte[10240];
                int reads = 0;
                while ((reads = inputStream.read(data)) > 0) {
                    String s = new String(data, 0, reads);
                    System.out.println("taskId: " + taskId + ", response from k8s cluster: " + s);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 查看日志
     */
    private static void testWatchConsole(String podName, KubernetesClient client) throws Exception {
        Pod pod = client.pods().inNamespace("default")
                .withName(podName)
                .get();

        String containerId = pod.getSpec().getContainers().get(0).getName();

        ExecWatch execWatch = client.pods().inNamespace("default")
                .withName(podName)
                .inContainer(containerId)
                .redirectingInput(10240)
                .redirectingOutput()
                .redirectingError()
                .withTTY()
                .exec("/bin/bash");

        executorService.execute(new StdTask(execWatch.getOutput(), "stdout"));
        executorService.execute(new StdTask(execWatch.getError(), "stderr"));

        Scanner scanner = new Scanner(System.in);
        OutputStream outputStream = execWatch.getInput();
        while (true) {
            String line = scanner.nextLine();
            if (line != null && line.length() > 0) {
                outputStream.write(line.getBytes(StandardCharsets.UTF_8));
                outputStream.flush();
            }
        }
    }

    private static void testWatchLog(String podName, KubernetesClient client) throws Exception {
        LogWatch logWatch = client.pods()
                .inNamespace("default")
                .withName(podName)
                .tailingLines(10)
                .watchLog();

        byte[] data = new byte[10240];
        int n = 0;
        InputStream inputStream = logWatch.getOutput();
        while ((n = inputStream.read(data)) > 0) {
            System.out.print(new String(data, 0, n));
        }
    }
}
